#define __STDC_CONSTANT_MACROS
#include "video_parser.h"
#include <iostream>
#include <ncurses.h>
#include <unistd.h>
#include <iostream>

//每个块宽 对应源视频的像素数
static uint32_t BLOCK_WIDTH = 4;  
//每个块高 对应源视频的像素数
static uint32_t  BLOCK_HEIGHT = 8;   
//每个块对应源视频的像素数
#define BLOCK_PIXS  (BLOCK_WIDTH*BLOCK_HEIGHT)  

// 宽 一共有多少块
#define SCREEN_WIDTH   190
// 高 一共有多少块
#define SCREEN_HEIGHT   75

static uint32_t  fps = 24;   

//待播放视频文件路径
std::string video_file;

#define requried(x) if (last) { std::cout << (x) << std::endl;return -1;}

//我们会按灰度将信息映射到下面十个字符上，从左往右，灰度依次增加
char steps[10] = {' ', '.', '.', '-', '-', '=', '=', '*', '*', '#'};

// 每当解码一帧视频数据时会调用该函数。该函数将灰度映射到字符并输出至terminal
void callback(unsigned char *buf, int wrap, int xsize, int ysize)
{
    int idx = 0;
    int x = 0;  // block x
    int y = 0;  // block y
    int vx = 0, vy = 0;  // video x, video y

    int total = 0;
    int mean = 0;

    int offset_x, offset_y;

    for (y = 0; y < SCREEN_HEIGHT; y++)
    {
        vx = 0;
        for (x = 0; x < SCREEN_WIDTH; x++)
        {
            total = 0;
            //整个 frame 被分成块， 我们计算每个块中像素的平均灰度
            for (vy = 0; vy < BLOCK_HEIGHT; vy++)
            {
                for (vx = 0; vx < BLOCK_WIDTH; vx++)
                {
                    offset_x = x*BLOCK_WIDTH  + vx ;
                    offset_y = y*BLOCK_HEIGHT + vy ;
                    if (offset_x > xsize)
                        continue;
                    if (offset_y > ysize)
                        continue;
                    total += buf[offset_y*xsize + offset_x];
                }
            }
            mean = total / BLOCK_PIXS;
            idx = mean / 26; // 10个阶度
            mvaddch(y ,x,steps[idx]);
        }
    }

    refresh();
    
    usleep((useconds_t) ((1.0 / fps)*1000000));
}

void print_help()
{
    std::cout << "ascii_player video_file [-bh 8] [-bw 4] [-fs 24]" << std::endl;
    std::cout << "\t -bh 指定每一块的高的像素数" << std::endl;
    std::cout << "\t -bw 指定每一块的宽的像素数" << std::endl;
    std::cout << "\t -fs 指定帧率" << std::endl;
}

int init_args(int argc, char *argv[])
{
    if (argc < 2)
    {
        std::cout << "错误： 必须指定一个输入文件作为命令行参数" << std::endl;
        print_help();
        return -1;
    }
    int idx = 1;
    bool last = false;
    bool match_video_file = false;
    for (idx = 1; idx < argc; idx++)
    {
        last = idx == argc-1;
        if (strcmp(argv[idx], "-bh") == 0)
        {
            requried("未指定值")
                
            BLOCK_HEIGHT = strtol(argv[++idx], nullptr, 10);
        }
        else if (strcmp(argv[idx], "-bw") == 0)
        {
            requried("未指定值")
                
            BLOCK_WIDTH = strtol(argv[++idx], nullptr, 10);
        }
        else if (strcmp(argv[idx], "-fs") == 0)
        {
            requried("未指定值")
            fps = strtol(argv[++idx], nullptr, 10);
        }
        else 
        {
            if (!match_video_file)
            {
                match_video_file = true;
                video_file = std::string(argv[idx]);
            }
            else 
            {
                std::cout << "错误：多次指定输入文件" << std::endl;
                return -1;
            }
        }
    }
    if (!match_video_file)
    {
        std::cout << "错误： 请指定输入文件参数" << std::endl;
        print_help();
        return -1;
    }
    return 0;
}
int main(int argc, char *argv[]) 
{
    if (init_args(argc, argv) < 0)
        return 0;

    initscr();
    clear();
    refresh();

    VideoParser parser(video_file);
    parser.setCallBack(callback);
    parser.decode();

    endwin();
    return 0;
}